/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2021 Marcus Britanicus (https://gitlab.com/marcusbritanicus)
 * Copyright (c) 2021 Abrar (https://gitlab.com/s96Abrar)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 **/


#include "desq-shell-unstable-v1-client-protocol.h"

#include "wayqt/DesQShell.hpp"
#include "wayqt/WayQtUtils.hpp"

WQt::DesQShell::DesQShell( zdesq_shell_manager_v1 *shellMgr ) {
    mObj = shellMgr;
}


WQt::DesQShell::~DesQShell() {
    zdesq_shell_manager_v1_destroy( mObj );
}


WQt::DesQOutput *WQt::DesQShell::getOutput( wl_output *wlOut ) {
    /**
     * We get the wfOut object. Now we need to send this to Output*
     * and hook it up to a listener.
     */
    zdesq_output_v1 *wfOut = zdesq_shell_manager_v1_get_desq_output( mObj, wlOut );

    return new WQt::DesQOutput( wfOut );
}


WQt::DesQSurface *WQt::DesQShell::getSurface( wl_surface *wlSurf ) {
    zdesq_surface_v1 *wfSurf = zdesq_shell_manager_v1_get_desq_surface( mObj, wlSurf );

    return new WQt::DesQSurface( wfSurf );
}


void WQt::DesQShell::setBackground( QWindow *window, QScreen *screen ) {
    wl_surface *bgSurf = WQt::Utils::wlSurfaceFromQWindow( window );
    wl_output  *bgOut  = WQt::Utils::wlOutputFromQScreen( screen );

    zdesq_shell_manager_v1_set_background( mObj, bgSurf, bgOut );
}


void WQt::DesQShell::setDropdown( QWindow *window, QScreen *screen ) {
    wl_surface *bgSurf = WQt::Utils::wlSurfaceFromQWindow( window );
    wl_output  *bgOut  = WQt::Utils::wlOutputFromQScreen( screen );

    zdesq_shell_manager_v1_set_dropdown( mObj, bgOut, bgSurf );
}


zdesq_shell_manager_v1 *WQt::DesQShell::get() {
    return mObj;
}


/**
 * Output Wrapper
 */

WQt::DesQOutput::DesQOutput( zdesq_output_v1 *wfOut ) {
    mObj = wfOut;
}


WQt::DesQOutput::~DesQOutput() {
    zdesq_output_v1_destroy( mObj );
}


void WQt::DesQOutput::setup() {
    zdesq_output_v1_add_listener( mObj, &mDesQOutputListener, this );
}


WQt::DesQHotSpot *WQt::DesQOutput::createHotSpot( HotSpotPoint hsPos, uint32_t threshold, uint32_t timeout ) {
    zdesq_hotspot_v1 *wfHS = zdesq_output_v1_create_hotspot( mObj, hsPos, threshold, timeout );

    return new WQt::DesQHotSpot( wfHS );
}


void WQt::DesQOutput::getWorkspaceExtents() {
    zdesq_output_v1_get_workspace_extents( mObj );
}


void WQt::DesQOutput::getActiveWorkspace() {
    zdesq_output_v1_get_active_workspace( mObj );
}


void WQt::DesQOutput::setActiveWorkspace( int row, int col ) {
    zdesq_output_v1_set_active_workspace( mObj, row, col );
}


zdesq_output_v1 *WQt::DesQOutput::get() {
    return mObj;
}


void WQt::DesQOutput::handleEnterFullScreen( void *data, zdesq_output_v1 * ) {
    DesQOutput *desqOpWrap = reinterpret_cast<DesQOutput *>(data);
    emit desqOpWrap->enteredFullScreen();
}


void WQt::DesQOutput::handleLeaveFullScreen( void *data, zdesq_output_v1 * ) {
    DesQOutput *desqOpWrap = reinterpret_cast<DesQOutput *>(data);
    emit desqOpWrap->leftFullScreen();
}


void WQt::DesQOutput::handleWorkspaceExtents( void *data, zdesq_output_v1 *, int rows, int columns ) {
    DesQOutput *desqOpWrap = reinterpret_cast<DesQOutput *>(data);
    emit desqOpWrap->workspaceExtentsChanged( rows, columns );
}


void WQt::DesQOutput::handleActiveWorkspace( void *data, zdesq_output_v1 *, int row, int column ) {
    DesQOutput *desqOpWrap = reinterpret_cast<DesQOutput *>(data);
    emit desqOpWrap->activeWorkspaceChanged( row, column );
}


void WQt::DesQOutput::handleViewAdded( void *data, zdesq_output_v1 *, uint32_t uuid, int row, int column ) {
    DesQOutput *desqOpWrap = reinterpret_cast<DesQOutput *>(data);

    emit desqOpWrap->viewAdded( uuid, row, column );
}


void WQt::DesQOutput::handleViewRemoved( void *data, zdesq_output_v1 *, uint32_t uuid, int row, int column ) {
    DesQOutput *desqOpWrap = reinterpret_cast<DesQOutput *>(data);

    emit desqOpWrap->viewRemoved( uuid, row, column );
}


void WQt::DesQOutput::handleDone( void *data, zdesq_output_v1 * ) {
    DesQOutput *desqOpWrap = reinterpret_cast<DesQOutput *>(data);
    emit desqOpWrap->done();
}


const struct zdesq_output_v1_listener WQt::DesQOutput::mDesQOutputListener = {
    .enter_fullscreen  = handleEnterFullScreen,
    .leave_fullscreen  = handleLeaveFullScreen,
    .workspace_extents = handleWorkspaceExtents,
    .active_workspace  = handleActiveWorkspace,
    .view_added        = handleViewAdded,
    .view_removed      = handleViewRemoved,
    .done              = handleDone,
};

/**
 * HotSpot Wrapper
 */

WQt::DesQHotSpot::DesQHotSpot( zdesq_hotspot_v1 *wfHS ) {
    mObj = wfHS;
}


WQt::DesQHotSpot::~DesQHotSpot() {
    zdesq_hotspot_v1_destroy( mObj );
}


void WQt::DesQHotSpot::setup() {
    zdesq_hotspot_v1_add_listener( mObj, &mWfHotSpotListener, this );
}


zdesq_hotspot_v1 *WQt::DesQHotSpot::get() {
    return mObj;
}


void WQt::DesQHotSpot::handleEnterHotSpot( void *data, zdesq_hotspot_v1 *wfHotspot ) {
    Q_UNUSED( wfHotspot );

    DesQHotSpot *wfHsWrap = reinterpret_cast<DesQHotSpot *>(data);
    emit wfHsWrap->enteredHotSpot();
}


void WQt::DesQHotSpot::handleLeaveHotSpot( void *data, zdesq_hotspot_v1 *wfHotspot ) {
    Q_UNUSED( wfHotspot );

    DesQHotSpot *wfHsWrap = reinterpret_cast<DesQHotSpot *>(data);
    emit wfHsWrap->leftHotSpot();
}


const struct zdesq_hotspot_v1_listener WQt::DesQHotSpot::mWfHotSpotListener = {
    handleEnterHotSpot,
    handleLeaveHotSpot,
};

/**
 * Surface Wrapper
 */

WQt::DesQSurface::DesQSurface( zdesq_surface_v1 *desq_surf ) {
    mObj = desq_surf;
}


WQt::DesQSurface::~DesQSurface() {
    zdesq_surface_v1_destroy( mObj );
}


void WQt::DesQSurface::move() {
    zdesq_surface_v1_interactive_move( mObj );
}


zdesq_surface_v1 *WQt::DesQSurface::get() {
    return mObj;
}
